package page

import "ibdreader/slice"

type IndexHeader struct {
	/**
	 * The size of the page directory in “slots”, which are each 16-bit byte offsets.
	 * Page directory中的slot个数.
	 */
	NumOfDirSlots int64

	/**
	 * The byte offset of the “end” of the currently used space.
	 * All space between the heap top and the end of the page directory is free space.
	 * 指向当前Page内已使用的空间的末尾位置，即free space的开始位置.
	 */
	HeapTopPosition int64

	/**
	 * records + infimum and supremum system records, and garbage (deleted) records.
	 * Page内所有记录个数，包含用户记录，系统记录以及标记删除的记录，同时当第一个bit设置为1时，
	 * 表示这个page 内是以Compact格式存储的.
	 */
	NumOfHeapRecords int64

	/**
	 * the high bit (0x8000) COMPACT and REDUNDANT.
	 */
	Format PageFormat

	/**
	 * A pointer to the first entry in the list of garbage (deleted) records.
	 * The list is singly-linked together using the “next record” pointers in each record header.
	 */
	FirstGarbageRecOffset int64

	/**
	 * 被删除的记录链表上占用的总的字节数，属于可回收的垃圾碎片空间.
	 */
	GarbageSpace int64

	/**
	 * 指向最近一次插入的记录偏移量，主要用于优化顺序插入操作.
	 */
	LastInsertPos int64

	/**
	 * LEFT, RIGHT, and NO_DIRECTION. sequential inserts (to the left [lower values] or right
	 * [higher values]) or random inserts. 用于指示当前记录的插入顺序以及是否正在进行顺序插入，每次插入时，
	 * PAGE_LAST_INSERT会和当前记录进行比较，以确认插入方向，据此进行插入优化.
	 */
	PageDirection PageDirection

	/**
	 * 当前以相同方向的顺序插入记录个数.
	 */
	NumOfInsertsInPageDirection int64

	/**
	 * non-deleted user records in the page.
	 * Page上有效的未被标记删除的用户记录个数.
	 */
	NumOfRecs int64

	/**
	 * 最近一次修改该page记录的事务ID，主要用于辅助判断二级索引记录的可见性.
	 */
	MaxTrxId int64

	/**
	 * Leaf pages are at level 0, and the level increments up the B+tree from there.
	 * In a typical 3-level B+tree, the root will be level 2,
	 * some number of internal non-leaf pages will be level 1, and leaf pages will be level 0.
	 * 该Page所在的btree level，根节点的level最大，叶子节点的level为0.
	 */
	PageLevel int64

	/**
	 * 该Page归属的索引ID.
	 */
	IndexId int64
}

func IndexHeaderReadSlice() IndexHeader {
	var ih IndexHeader
	ih.NumOfDirSlots = slice.ReadUnsignedShort()
	ih.HeapTopPosition = slice.ReadUnsignedShort()
	flag := slice.ReadShortInt16()
	ih.NumOfHeapRecords = flag & (0x7fff)
	ih.Format = FormatFind((flag & 0x8000) >> 15)
	ih.FirstGarbageRecOffset = slice.ReadUnsignedShort()
	ih.GarbageSpace = slice.ReadUnsignedShort()
	ih.LastInsertPos = slice.ReadUnsignedShort()
	ih.PageDirection = PageDirectionFind(slice.ReadUnsignedShort())
	ih.NumOfInsertsInPageDirection = slice.ReadUnsignedShort()
	ih.NumOfRecs = slice.ReadUnsignedShort()
	ih.MaxTrxId = slice.ReadLongInt64()
	ih.PageLevel = slice.ReadUnsignedShort()
	ih.IndexId = slice.ReadLongInt64()
	return ih
}

func FormatFind(format int64) PageFormat {
	var pf PageFormat
	if format == REDUNDANT {
		pf = "REDUNDANT"
	} else if format == COMPACT {
		pf = "COMPACT"
	} else {
		pf = ""
	}
	return pf
}

func PageDirectionFind(pageD int64) PageDirection {
	var pd PageDirection
	if pageD == LEFT {
		pd = "LEFT"
	} else if pageD == RIGHT {
		pd = "RIGHT"
	} else if pageD == SAME_REC {
		pd = "SAME_REC"
	} else if pageD == SAME_PAGE {
		pd = "SAME_PAGE"
	} else if pageD == NO_DIRECTION {
		pd = "NO_DIRECTION"
	} else {
		pd = ""
	}
	return pd
}
